#pragma once 

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <queue>

namespace qds
{
    const int task_num = 5;

    template <class T>
    class thread_pool
    {
    public:
    thread_pool(int num = task_num)
        :_num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~thread_pool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void push_task(const T& in)
    {
        lock();
        _task_queue.push(in);
        unlock();
        //任务队列里面有任务了,可以唤醒线程来执行任务
        wake_up();
    }

    void pop_task(T* out)
    {
        *out = _task_queue.front();
        _task_queue.pop();
    }

    //在类中要让线程执行类内成员函数方法是不行
    //因为线程执行的函数参数要求有且唯一为void*类型
    //但是如果是类内成员函数,那么第一个会是隐藏的this指针
    //所以这里使用static函数
    static void* rountine(void* args)
    {
        pthread_detach(pthread_self());
        thread_pool<T>* tp = (thread_pool* )args;

        while(true)
        {
            tp->lock();

            //这里使用while循环,预防伪唤醒带来的错误
            while (tp->is_empty())
            {
                //任务队列为空,线程进行等待
                tp->wait();
            }
            
            //到这里说明任务队列里面有任务了
            T t;
            tp->pop_task(&t); 

            tp->unlock();
            
            t();
        }
    }

    void init_thread_pool()
    {
        pthread_t tid[_num];

        for(int i = 0; i < _num; ++i)
        {                                              //这里把自己这个类传进去,因为会使用类的成员变量和函数
            pthread_create(tid + i, nullptr, rountine, (void* )this);
        }
        
        //给所有的线程时间,让他们有时间完成分离线程的操作
        usleep(1000); 
    }

    private:
    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void wait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void wake_up()
    {
        pthread_cond_signal(&_cond);
    }

    bool is_empty()
    {
        return _task_queue.empty();
    }
        
    private:
        //线程池中线程的数量
        int _num;
        //临界资源
        std::queue<T> _task_queue;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
    };

}
